﻿using JESAI.HttpRequestMonitor.Core.Abstracts;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Schema;
using JESAI.HttpRequestMonitor.Options;
using System;

namespace JESAI.HttpRequestMonitor.Builders
{
    /// <summary>
    /// 请求信息模型构建器基类
    /// </summary>
    internal abstract class BaseRequestModelBuilder : IRequestModelBuilder
    {
        /// <summary>
        /// 选项参数
        /// </summary>
        protected HttpRequestMonitorOptions Options { get; }

        /// <summary>
        /// 实体创建器
        /// </summary>
        protected IModelCreator ModelCreator { get; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public BaseRequestModelBuilder(IModelCreator modelCreator, IOptions<HttpRequestMonitorOptions> options)
        {
            Options = options.Value;
            ModelCreator = modelCreator;
        }

        /// <summary>
        /// 抽象方法，用于构建请求信息模型
        /// </summary>
        /// <param name="context"> HTTP 请求上下文 </param>
        /// <param name="requestModel"> 请求信息模型 </param>
        /// <param name="path"> 请求路径 </param>
        /// <returns></returns>
        protected abstract (IRequestModel, IRequestDetailModel) Build(HttpContext context, IRequestModel requestModel, string path);


        public (IRequestModel, IRequestDetailModel) Build(HttpContext context, Stopwatch stopwatch)
        {
            //获取请求路径
            var path = (context.Request.Path.HasValue ? context.Request.Path.Value : string.Empty).ToLowerInvariant();

            if (IsFilterHttpRequest(context, path))
            {
                return (null, null);
            }

            //构建请求信息模型
            IRequestModel requestModel = ModelCreator.CreateRequestModel();
            requestModel.IP = context.Connection.RemoteIpAddress.ToString();
            requestModel.Port = context.Connection.RemotePort;
            requestModel.LocalIP = context.Connection.LocalIpAddress.ToString();
            requestModel.LocalPort = context.Connection.LocalPort;
            requestModel.StatusCode = context.Response.StatusCode;
            requestModel.Method = context.Request.Method;
            requestModel.Url = context.Request.Path;
            requestModel.RequestType = context.Request.ContentType == "application/grpc" ? "grpc" : "http";
            requestModel.Milliseconds = (int)stopwatch.ElapsedMilliseconds;
            requestModel.CreateTime = context.Items[SysConst.ActiveTraceCreateTime].ToDateTime();

            path = path.Replace(@"///", "/").Replace(@"//", "/");

            var (rtnRequestModel, rtnRequestDetailModel) = Build(context, requestModel, path);

            return (HandleRequestModelAttributeNull(rtnRequestModel), HandleRequestDetailModel(rtnRequestDetailModel));
        }

        /// <summary>
        /// 处理请求信息模型属性为空的情况
        /// </summary>
        /// <param name="requestModel"></param>
        /// <returns></returns>
        private IRequestModel HandleRequestModelAttributeNull(IRequestModel requestModel)
        {
            if (requestModel.Node == null) requestModel.Node = string.Empty;
            if (requestModel.Route == null) requestModel.Route = string.Empty;
            if (requestModel.Url == null) requestModel.Url = string.Empty;
            if (requestModel.Method == null) requestModel.Method = string.Empty;
            if (requestModel.IP == null) requestModel.IP = string.Empty;

            return requestModel;
        }

        private IRequestDetailModel HandleRequestDetailModel(IRequestDetailModel request)
        {
            if (request.Scheme == null) request.Scheme = string.Empty;
            if (request.QueryString == null) request.QueryString = string.Empty;
            if (request.RequestHeader == null) request.RequestHeader = string.Empty;
            if (request.Cookie == null) request.Cookie = string.Empty;
            if (request.RequestBody == null) request.RequestBody = string.Empty;
            if (request.ResponseBody == null) request.ResponseBody = string.Empty;
            if (request.ErrorMessage == null) request.ErrorMessage = string.Empty;
            if (request.ErrorStackTrace == null) request.ErrorStackTrace = string.Empty;

            int max = SysConst.HttpRequestMonitorFieldMaxLength;

            if (request.QueryString.Length > max)
            {
                request.QueryString = request.QueryString.Substring(0, max);
            }

            if (request.RequestHeader.Length > max)
            {
                request.RequestHeader = request.RequestHeader.Substring(0, max);
            }

            if (request.Cookie.Length > max)
            {
                request.Cookie = request.Cookie.Substring(0, max);
            }

            if (request.RequestBody.Length > max)
            {
                request.RequestBody = request.RequestBody.Substring(0, max);
            }

            if (request.ResponseBody.Length > max)
            {
                request.ResponseBody = request.ResponseBody.Substring(0, max);
            }

            if (request.ErrorMessage.Length > max)
            {
                request.ErrorMessage = request.ErrorMessage.Substring(0, max);
            }

            if (request.ErrorStackTrace.Length > max)
            {
                request.ErrorStackTrace = request.ErrorStackTrace.Substring(0, max - 10);
            }

            return request;
        }

        /// <summary>
        /// 是否过滤HTTP请求
        /// </summary>
        /// <param name="context"> HTTP 请求上下文 </param>
        /// <param name="path"> 请求路径 </param>
        /// <returns></returns>
        private bool IsFilterHttpRequest(HttpContext context, string path)
        {
            bool result = false;

            //是否GRPC请求
            if (!string.IsNullOrWhiteSpace(context.Request.ContentType) && context.Request.ContentType.ToLower().Contains("application/grpc"))
            {
                return true;
            }

            //是否OPTIONS请求
            if (context.Request.Method.ToLowerInvariant() == "options")
            {
                return true;
            }

            //是否过滤静态文件
            if (!Options.FilterStaticFile)
            {
                return false;
            }

            if (path.Contains("."))
            {
                var fileType = path.Split('.').Last().ToLowerInvariant();
                if (fileType != "html" && fileType != "htm" && fileType != "aspx")
                {
                    return true;
                }
            }

            return result;

        }
    }
}
